package com.xiaobaibai.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xiaobaibai.bo.pay.Amount;
import com.xiaobaibai.bo.pay.Payer;
import com.xiaobaibai.bo.pay.WxPayCreateOrder;
import com.xiaobaibai.common.OrderCommon;
import com.xiaobaibai.common.OrderEnum;
import com.xiaobaibai.common.PayCommon;
import com.xiaobaibai.common.WeixinCommon;
import com.xiaobaibai.entity.Order;
import com.xiaobaibai.entity.User;
import com.xiaobaibai.response.ResponseFormat;
import com.xiaobaibai.service.IOrderService;
import com.xiaobaibai.service.IPaymentRecordService;
import com.xiaobaibai.service.IUserService;
import com.xiaobaibai.units.pay.KeyPairFactory;
import com.xiaobaibai.units.PayHttpUnit;
import com.xiaobaibai.units.SecurityUnit;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@Api(tags = "支付回调接口")
@RequestMapping("/pay")
@CrossOrigin
@Slf4j
public class PayController {

    @Autowired
    private IPaymentRecordService paymentRecordService;

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IUserService userService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private final String payMap="PAYMAP:";

    private static final String description="民安优选绿色到家";

    @PostMapping("/orderPay")
    @ApiOperation("调起支付")
    public ResponseFormat touchPay(@RequestBody String orderId){

        String s = stringRedisTemplate.opsForValue().get(payMap + orderId);
        if(s!=null){
            HashMap map = JSON.parseObject(s, HashMap.class);
            return ResponseFormat.ok("下单信息获取成功",map);
        }

        Integer userId = SecurityUnit.getUserId();
        Boolean flag = stringRedisTemplate.hasKey(OrderCommon.doOrderLock + userId);
        if(flag)//存在订单锁
            return ResponseFormat.failure("系统繁忙,请稍后支付");
        stringRedisTemplate.opsForValue().set(OrderCommon.doOrderLock+userId,"1",5, TimeUnit.SECONDS);

        QueryWrapper<Order> q1=new QueryWrapper<>();
        q1.select("user_id","order_real_price","order_status");
        q1.eq("order_id",orderId);
        Order order = orderService.getOne(q1);
        if(!order.getOrderStatus().equals(OrderEnum.NOPAY.getCode())
                &&!order.getOrderStatus().equals(OrderEnum.FACETO.getCode())){
            //非等待支付状态就不可支付
            return ResponseFormat.failure("当前订单状态不可支付");
        }
        if(!order.getUserId().equals(userId)){
            //非本人订单也不可支付
            return ResponseFormat.failure("非本人订单不可支付");
        }
        //签名两次,返回可用信息
        QueryWrapper<User> q2=new QueryWrapper<>();
        q2.select("user_openid");
        q2.eq("user_id",userId);
        User user = userService.getOne(q2);
        int penny = (int) (order.getOrderRealPrice().doubleValue()*100);
        WxPayCreateOrder wxPayCreateOrder=
                new WxPayCreateOrder(new Payer(user.getUserOpenid()),
                        new Amount(penny),orderId,description);
        String wxOrder = PayHttpUnit.createWxPayOrder(wxPayCreateOrder);
        log.info("微信预下单订单:{}",wxOrder);
        if(wxOrder==null){
            return ResponseFormat.failure("系统繁忙");
        }
        wxOrder="prepay_id="+wxOrder;
        String uuid=UUID.randomUUID().toString().substring(0,32);
        long timestamp=System.currentTimeMillis()/1000;

        String paySign = KeyPairFactory.signTwo(WeixinCommon.APPID, timestamp,
                uuid, wxOrder, KeyPairFactory.createPKCS12());

        Map<String,String> map=new HashMap<>();
        map.put("package",wxOrder);
        map.put("nonceStr",uuid);
        map.put("timeStamp",String.valueOf(timestamp));
        map.put("paySign",paySign);

        //缓存支付信息14分钟40秒
        stringRedisTemplate.opsForValue().set(payMap+orderId,JSON.toJSONString(map),880,TimeUnit.SECONDS);

        return ResponseFormat.ok("下单信息获取成功",map);
    }


    @PostMapping("/payNotifyUrl")
    @ApiOperation("订单支付回调")
    @ApiIgnore
    public Map<String,String> payNotifyUrl(HttpServletRequest request){
        Map<String,String> map=new HashMap<>();
        System.out.println("--------------");
        System.out.println("接收到了订单支付的回调");
        String s = this.ReadAsChars(request);
        JSONObject jsonObject = JSONObject.parseObject(s);
        JSONObject o1 = jsonObject.getJSONObject("resource");
        if(o1==null){
            map.put("code","error");
            map.put("message","参数残缺");
            return map;
        }
        String associatedData = o1.getString("associated_data");
        String nonce=o1.getString("nonce");
        String ciphertext=o1.getString("ciphertext");
        if(associatedData==null||nonce==null||ciphertext==null){
            map.put("code","error");
            map.put("message","参数残缺");
            return map;
        }
        String responseBody=null;
        try {//检验结果是否正确
            responseBody = KeyPairFactory.decryptResponseBody(
                    PayCommon.apiV3Key,
                    associatedData,
                    nonce,
                    ciphertext
            );
        }catch (Exception e){
            map.put("code","error");
            map.put("message","非法回调");
            return map;
        }
        System.out.println("--------------");
        JSONObject result = JSONObject.parseObject(responseBody);
        System.out.println(JSON.toJSONString(result));
        paymentRecordService.payNotify(result);//保存记录,在里面修改订单状态
        map.put("code","SUCCESS");
        map.put("message","成功接收");
        return map;
    }

    private String ReadAsChars(HttpServletRequest request) {

        BufferedReader br = null;
        StringBuilder sb = new StringBuilder("");
        try
        {
            br = request.getReader();
            String str;
            while ((str = br.readLine()) != null)
            {
                sb.append(str);
            }
            br.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != br)
            {
                try
                {
                    br.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

}
